/*
Copyright (C) 2001, 2010 United States Government
as represented by the Administrator of the
National Aeronautics and Space Administration.
All Rights Reserved.
*/

package gov.nasa.worldwind.util.xml;

import gov.nasa.worldwind.util.Logging;

import javax.xml.stream.*;
import javax.xml.stream.events.XMLEvent;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author tag
 * @version $Id: BasicXMLEventParserContext.java 13107 2010-02-06 08:25:24Z tgaskins $
 */
public class BasicXMLEventParserContext implements XMLEventParserContext
{
    protected XMLEventReader reader;
    protected StringXMLEventParser stringParser;
    protected DoubleXMLEventParser doubleParser;

    protected ConcurrentHashMap<String, XMLEventParser> defaultParsers
        = new ConcurrentHashMap<String, XMLEventParser>();

    public BasicXMLEventParserContext(XMLEventReader eventReader)
    {
        this.reader = eventReader;

        this.initializeDefaultParsers();
    }

    protected void initializeDefaultParsers()
    {
        this.defaultParsers.put("String", new StringXMLEventParser());
        this.defaultParsers.put("Double", new DoubleXMLEventParser());
    }

    public XMLEventReader getEventReader()
    {
        return this.reader;
    }

    public boolean hasNext()
    {
        return this.getEventReader().hasNext();
    }

    public XMLEvent nextEvent() throws XMLStreamException
    {
        while (this.hasNext())
        {
            XMLEvent event = this.getEventReader().nextEvent();

            if (event.getEventType() == XMLEvent.CHARACTERS && event.asCharacters().isWhiteSpace())
                continue;
            
            return event;
        }

        return null;
    }

    public XMLEventParser getParser(XMLEvent event)
    {
        if (event == null)
        {
            String message = Logging.getMessage("nullValue.EventIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        String localName = event.asStartElement().getName().getLocalPart();

        return localName != null ? this.getParser(localName) : null;
    }

    public StringXMLEventParser getStringParser()
    {
        return (StringXMLEventParser) this.getParser("String");
    }

    public DoubleXMLEventParser getDoubleParser()
    {
        return (DoubleXMLEventParser) this.getParser("Double");
    }

    public String getCharacters(XMLEvent event)
    {
        if (event == null)
        {
            String message = Logging.getMessage("nullValue.EventIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        return event.getEventType() == XMLEvent.CHARACTERS ? event.asCharacters().getData() : null;
    }

    public boolean isStartElement(XMLEvent event, String elementName)
    {
        if (event == null)
        {
            String message = Logging.getMessage("nullValue.EventIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        if (elementName == null)
        {
            String message = Logging.getMessage("nullValue.ElementNameIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        return isStartElementEvent(event, elementName);
    }

    public boolean isStartElement(XMLEvent event)
    {
        if (event == null)
        {
            String message = Logging.getMessage("nullValue.EventIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        return isStartElementEvent(event);
    }

    public boolean isEndElement(XMLEvent event, XMLEvent startElement)
    {
        if (event == null || startElement == null)
        {
            String message = Logging.getMessage("nullValue.EventIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        return isEndElementEvent(event, startElement);
    }

    public static boolean isStartElementEvent(XMLEvent event, String elementName)
    {
        if (event == null)
        {
            String message = Logging.getMessage("nullValue.EventIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        if (elementName == null)
        {
            String message = Logging.getMessage("nullValue.ElementNameIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        return (event.getEventType() == XMLEvent.START_ELEMENT
            && event.asStartElement().getName().getLocalPart().equalsIgnoreCase(elementName));
    }

    public static boolean isStartElementEvent(XMLEvent event)
    {
        if (event == null)
        {
            String message = Logging.getMessage("nullValue.EventIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        return event.getEventType() == XMLEvent.START_ELEMENT;
    }

    public static boolean isEndElementEvent(XMLEvent event, XMLEvent startElement)
    {
        if (event == null || startElement == null)
        {
            String message = Logging.getMessage("nullValue.EventIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        return (event.getEventType() == XMLEvent.END_ELEMENT
            && event.asEndElement().getName().getLocalPart().equalsIgnoreCase(
            startElement.asStartElement().getName().getLocalPart()));
    }

    public void registerParser(XMLEventParser parser, String localName)
    {
        if (parser == null)
        {
            String message = Logging.getMessage("nullValue.ParserIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        if (localName == null)
        {
            String message = Logging.getMessage("nullValue.ElementNameIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        this.defaultParsers.put(localName, parser);
    }

    public void unregisterParser(XMLEventParser parser)
    {
        if (parser == null)
        {
            String message = Logging.getMessage("nullValue.ParserIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        String parserKey = null;

        for (Map.Entry<String,XMLEventParser> entry : this.defaultParsers.entrySet())
        {
            if (entry.getValue() == parser)
            {
                parserKey = entry.getKey();
                break;
            }
        }

        if (parserKey != null)
            this.defaultParsers.remove(parserKey);
    }

    public XMLEventParser getParser(String localName)
    {
        if (localName == null)
        {
            String message = Logging.getMessage("nullValue.ElementNameIsNull");
            Logging.logger().severe(message);
            throw new IllegalArgumentException(message);
        }

        return this.defaultParsers.get(localName);
    }
}
